#include <UITest.h>
#include <MainWindow.h>

namespace pp
{
    UITest::UITest()
    {
        mpEngine = ne::Engine::GetSingletonPtr();
        mpRenderSystem = mpEngine->getRenderSystem();

        mpMouse = mpEngine->getMouse();
        mMousePosition = mpMouse->getPosition();

        mpTimer = new ne::Timer();
        mpTimer->reset();

        mpAtlas.bind(new ne::Atlas(0, 0, "DefaultUIAtlas", "../ui/atlas/default_ui_atlas.xml", false, 0));
        mpAtlas->load();

        mpUIWindow = new ne::UIWindow("PianoProgram Main Window");
        mpUIWindow->setFont(mpEngine->getFont());
        mpUIWindow->setAtlas(mpAtlas);
        mpUIWindow->setSprite("Window");
        //mpUIWindow->setAlignType(ne::TAT_CENTER);
        mpUIWindow->setPosition(ne::Vector3(-256.0f, -128.0f, -500.0f));
        mpUIWindow->setScale(ne::Vector3(1.0f, 0.5f, 1.0f));
        mpUIWindow->setSize(512.0f, 256.0f);

        ne::UIObject *pUIObject = new ne::UIObject();
        pUIObject->setSprite("LightBorderBlackBox");
        pUIObject->setPosition(ne::Vector3(8.0f, 216.0f, 0.0f));
        pUIObject->setSize(32.0f, 32.f);
        mpUIWindow->addChild(pUIObject);

        pUIObject = new ne::UIObject();
        pUIObject->setSprite("BlackBorderDarkBox");
        pUIObject->setPosition(ne::Vector3(468.0f, 216.0f, 0.0f));
        pUIObject->setSize(32.0f, 32.f);
        mpUIWindow->addChild(pUIObject);

        pUIObject = new ne::UIObject();
        pUIObject->setSprite("BlackBorderLightBox");
        pUIObject->setPosition(ne::Vector3(8.0f, 12.0f, 0.0f));
        pUIObject->setSize(32.0f, 32.f);
        mpUIWindow->addChild(pUIObject);

        pUIObject = new ne::UIObject();
        pUIObject->setSprite("LightBorderDarkBox");
        pUIObject->setPosition(ne::Vector3(468.0f, 12.0f, 0.0f));
        pUIObject->setSize(32.0f, 32.f);
        mpUIWindow->addChild(pUIObject);

        ne::UILabel *pUILabel = new ne::UILabel();
        pUILabel->setSprite("BlackBorderDarkBox");
        pUILabel->setAlignType(ne::TAT_TOP);
        pUILabel->setFontLayout(ne::FL_HORIZONTAL);
        pUILabel->setText("Piano Program");
        pUILabel->setTextColor(ne::UI_COLOR_SKY);
        pUILabel->setColor(ne::UI_COLOR_LIGHT);
        pUILabel->setPosition(ne::Vector3(256.0f, 128.0f, 0.0f));
        //pUILabel->yaw(ne::Math::QUARTER_PI);
        //pUILabel->pitch(ne::Math::QUARTER_PI);
        pUILabel->setScale(ne::Vector3(2.0f, 4.0f, 1.0f));
        pUILabel->setSize(200.0f, 32.f);
        mpUIWindow->addChild(pUILabel);


        ne::GLSLManager *pManager = mpEngine->getGLSLManager();
        ne::GLSLProgramPtr pProgram = pManager->create("DefaultUI", "../ui/shader/default_ui.glpg", true);
        ne::GLSLShaderPtr pVShader = pProgram->createShaderFromFile("DefaultUIVertexShader", "../ui/shader/default_ui.glvs", ne::SHADER_TYPE_VERTEX);
        ne::GLSLShaderPtr pFShader = pProgram->createShaderFromFile("DefaultUIFragmentShader", "../ui/shader/default_ui.glfs", ne::SHADER_TYPE_FRAGMENT);
        pProgram->attachShader(pVShader);
        pProgram->attachShader(pFShader);
        pProgram->setAttribLocation(uint32_t(ne::VAS_POSITION), "nePosition");
        pProgram->setAttribLocation(uint32_t(ne::VAS_COLOR), "neColor");
        pProgram->setAttribLocation(uint32_t(ne::VAS_TEXTURE_COORD), "neTexCoord");
        pProgram->link();
        pProgram->validate();

        mpAtlasMaterial.bind(new ne::Material(0, 0, "AtlasMaterial", "", true, 0));
        mpAtlasMaterial->setProgram(pProgram);
        mpAtlasMaterial->setTexture("neMainMap", mpAtlas->getTexture());

        pProgram = pManager->create("DefaultFont", "../ui/shader/default_font.glpg", true);
        pVShader = pProgram->createShaderFromFile("DefaultUIVertexShader", "../ui/shader/default_font.glvs", ne::SHADER_TYPE_VERTEX);
        pFShader = pProgram->createShaderFromFile("DefaultUIFragmentShader", "../ui/shader/default_font.glfs", ne::SHADER_TYPE_FRAGMENT);
        pProgram->attachShader(pVShader);
        pProgram->attachShader(pFShader);
        pProgram->setAttribLocation(uint32_t(ne::VAS_POSITION), "nePosition");
        pProgram->setAttribLocation(uint32_t(ne::VAS_COLOR), "neColor");
        pProgram->setAttribLocation(uint32_t(ne::VAS_TEXTURE_COORD), "neTexCoord");
        pProgram->link();
        pProgram->validate();

        mpFontMaterial.bind(new ne::Material(0, 0, "FontMaterial", "", true, 0));
        mpFontMaterial->setProgram(pProgram);
        mpFontMaterial->setTexture("neMainMap", mpUIWindow->getFont()->getTexture());

        mpAtlasPrimitive.bind(new ne::PrimitiveDeclaration());
        mpFontPrimitive.bind(new ne::PrimitiveDeclaration());
    }

    bool UITest::tick()
    {
        double interval = mpTimer->getIntervalSeconds();

        mpUIWindow->roll(ne::Math::QUARTER_PI * interval * 0.1f);
        mpUIWindow->yaw(ne::Math::QUARTER_PI * interval * 0.2f);
        mpUIWindow->pitch(ne::Math::QUARTER_PI * interval * 0.3f);
        mpUIWindow->update();

        mMousePosition = mpMouse->getPosition();
        ne::Ray outRay;
        MainWindow::GetSingleton().getViewport()->getScreenToWorldRay(mMousePosition.x, mMousePosition.y, outRay);
        mMousePosition.x = outRay.origin.x;
        mMousePosition.y = outRay.origin.y;
        mpUIWindow->trace(outRay);

        mpUIWindow->updateGeometry();

        mpAtlasPrimitive->removeAll();
        ne::DynamicGeometryPtr pGeometry = mpUIWindow->getAtlasGeometry();
        if (pGeometry.notNull())
        {
            mpAtlasPrimitive->setPrimitiveType(pGeometry->getPrimitiveType());
            ne::VertexDataPtr vd = pGeometry->getVertexData();
            if (vd.notNull())
            {
                mpAtlasPrimitive->addVertexAttribute(vd->getAttribute(ne::VAS_POSITION));
                mpAtlasPrimitive->addVertexAttribute(vd->getAttribute(ne::VAS_COLOR));
                mpAtlasPrimitive->addVertexAttribute(vd->getAttribute(ne::VAS_TEXTURE_COORD));
            }
            ne::IndexDataPtr id = pGeometry->getIndexData();
            if (id.notNull())
            {
                mpAtlasPrimitive->addIndexAttribute(id->getAttribute());
            }
        }

        mpFontPrimitive->removeAll();
        pGeometry = mpUIWindow->getFontGeometry();
        if (pGeometry.notNull())
        {
            mpFontPrimitive->setPrimitiveType(pGeometry->getPrimitiveType());
            ne::VertexDataPtr vd = pGeometry->getVertexData();
            if (vd.notNull())
            {
                mpFontPrimitive->addVertexAttribute(vd->getAttribute(ne::VAS_POSITION));
                mpFontPrimitive->addVertexAttribute(vd->getAttribute(ne::VAS_COLOR));
                mpFontPrimitive->addVertexAttribute(vd->getAttribute(ne::VAS_TEXTURE_COORD));
            }
            ne::IndexDataPtr id = pGeometry->getIndexData();
            if (id.notNull())
            {
                mpFontPrimitive->addIndexAttribute(id->getAttribute());
            }
        }

        return true;
    }

    bool UITest::render()
    {
        /* TODO: Debug
        mpRenderSystem->setPolygonMode(ne::PM_LINE);
        */

        ne::RenderPass pass;
        pass.option.depthTestEnable = false;
        pass.option.depthWriteEnable = false;
        pass.option.cullFaceEnable = false;
        pass.option.blendEnable = true;
        pass.material = mpAtlasMaterial;
        pass.primitive = mpAtlasPrimitive;
        mpRenderSystem->render(pass);

        pass.material = mpFontMaterial;
        pass.primitive = mpFontPrimitive;
        mpRenderSystem->render(pass);

        glPushMatrix();
        glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
        glBegin(GL_QUADS);
            glVertex3f(-640.0f, -350.0f, 0.0f);
            glVertex3f(-640.0f, -360.0f, 0.0f);
            glVertex3f(640.0f, -360.0f, 0.0f);
            glVertex3f(640.0f, -350.0f, 0.0f);
        glEnd();

        glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
        glBegin(GL_QUADS);
            glVertex3f(-640.0f, 360.0f, 0.0f);
            glVertex3f(-640.0f, 350.0f, 0.0f);
            glVertex3f(640.0f, 350.0f, 0.0f);
            glVertex3f(640.0f, 360.0f, 0.0f);
        glEnd();

        glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
        glBegin(GL_LINES);
            glVertex3f(mMousePosition.x, -360.0f, 0.0f);
            glVertex3f(mMousePosition.x, 360.0f, 0.0f);
            glVertex3f(-640.0f, mMousePosition.y, 0.0f);
            glVertex3f(640.0f, mMousePosition.y, 0.0f);
        glEnd();
        glPopMatrix();

        /* TODO: Debug
        mpRenderSystem->setPolygonMode(ne::PM_FILL);
        */

        return true;
    }

    UITest::~UITest()
    {
        delete mpUIWindow;
    }

    UITest& UITest::GetSingleton()
    {
        assert(mpInstance);
        return *mpInstance;
    }

    UITest* UITest::GetSingletonPtr()
    {
        return mpInstance;
    }
}
